home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / HippoDraw / HippoDrawSrc1.1 / Hippo.subproj / SyncScrollView.m < prev    next >
Encoding:
Text File  |  1992-04-25  |  8.5 KB  |  330 lines

  1. #import "SyncScrollView.h"
  2. #import <appkit/ClipView.h>
  3.  
  4. /*
  5.  * Any View that responds to these messages can be a "ruler".
  6.  * This is a nice way to make an object which works in concert
  7.  * with another object, but isn't hardwired into the implementation
  8.  * of that object and, instead, publishes a minimal interface
  9.  * which it expects another object to respond to.
  10.  */
  11.  
  12. @interface View(Ruler)
  13. - setFlipped:(BOOL)flag;        /* if YES, coordinates go right->left or top->bottom */
  14. - hidePosition;                /* hide any positioning markers */
  15. - showPosition:(NXCoord)p :(NXCoord)q;    /* put the positioning markers at p and q */
  16. @end
  17.  
  18. @implementation SyncScrollView
  19. /*
  20.  * This subclass of ScrollView is extremely useful for programmers
  21.  * who want some View to scroll along with a main docView.  A good
  22.  * example is a spreadsheet that wants its column and row headings
  23.  * to scroll along with the cells in the spreadsheet itself.
  24.  * It is actually quite simple.  We simply override tile to place
  25.  * two ClipViews with our views (rulers in this case) in them into
  26.  * the view hierarchy, then override scrollClip:to: to update their
  27.  * drawing origins when the docView is scrolled.  We also override
  28.  * reflectScroll: since we don't want that to apply to our little
  29.  * ruler views, only to the main docView.
  30.  */
  31.  
  32. - setRulerClass:factoryId
  33. {
  34.     rulerClass = factoryId;
  35.     return self;
  36. }
  37.  
  38. - setRulerWidths:(NXCoord)horizontal :(NXCoord)vertical
  39. {
  40.     horizontalRulerWidth = horizontal;
  41.     verticalRulerWidth = vertical;
  42.     return self;
  43. }
  44.  
  45. - (BOOL)bothRulersAreVisible
  46. {
  47.     return verticalRulerIsVisible && horizontalRulerIsVisible;
  48. }
  49.  
  50. - (BOOL)eitherRulerIsVisible
  51. {
  52.     return verticalRulerIsVisible || horizontalRulerIsVisible;
  53. }
  54.  
  55. - (BOOL)verticalRulerIsVisible
  56. {
  57.     return verticalRulerIsVisible;
  58. }
  59.  
  60. - (BOOL)horizontalRulerIsVisible
  61. {
  62.     return horizontalRulerIsVisible;
  63. }
  64.  
  65. - setRulerOrigin:(RulerOrigin)origin
  66. {
  67.     RulerOrigin oldRulerOrigin = rulerOrigin;
  68.  
  69.     rulerOrigin = origin;
  70.     switch (origin) {
  71.     case LowerRight:
  72.         [[hClipRuler docView] setFlipped:YES];
  73.         break;
  74.     case UpperRight:
  75.         [[hClipRuler docView] setFlipped:YES];
  76.     case UpperLeft:
  77.         [[vClipRuler docView] setFlipped:YES];
  78.     case LowerLeft:
  79.         break;
  80.     default:
  81.         rulerOrigin = oldRulerOrigin;
  82.         break;
  83.     }
  84.  
  85.     return self;
  86. }
  87.  
  88. - makeRulers
  89. /*
  90.  * This makes the rulers.
  91.  * We do this lazily in case the user never asks for the rulers.
  92.  */
  93. {
  94.     id ruler;
  95.     NXRect aRect, bRect;
  96.  
  97.     if (!rulerClass || (!horizontalRulerWidth && !verticalRulerWidth)) return nil;
  98.  
  99.     if (horizontalRulerWidth) {
  100.     [[contentView docView] getFrame:&aRect];
  101.     NXDivideRect(&aRect, &bRect, horizontalRulerWidth, NX_YMIN);
  102.     hClipRuler = [[ClipView allocFromZone:[self zone]] init];
  103.     ruler = [[rulerClass allocFromZone:[self zone]] initFrame:&bRect];
  104.     [hClipRuler setDocView:ruler];
  105.     }
  106.     if (verticalRulerWidth) {
  107.     [[contentView docView] getFrame:&aRect];
  108.     NXDivideRect(&aRect, &bRect, verticalRulerWidth, NX_XMIN);
  109.     vClipRuler = [[ClipView allocFromZone:[self zone]] init];
  110.     ruler = [[rulerClass allocFromZone:[self zone]] initFrame:&bRect];
  111.     [vClipRuler setDocView:ruler];
  112.     }
  113.     [self setRulerOrigin:rulerOrigin];
  114.     rulersMade = 1;
  115.  
  116.     return self;
  117. }
  118.  
  119. - updateRulers:(const NXRect *)rect
  120. {
  121.     if (!rect) {
  122.     if (verticalRulerIsVisible) {
  123.         [[vClipRuler docView] hidePosition];
  124.     }
  125.     if (verticalRulerIsVisible) {
  126.         [[hClipRuler docView] hidePosition];
  127.     }
  128.     } else {
  129.     if (verticalRulerIsVisible) {
  130.         [[vClipRuler docView] showPosition:rect->origin.y :rect->origin.y + rect->size.height];
  131.     }
  132.     if (verticalRulerIsVisible) {
  133.         [[hClipRuler docView] showPosition:rect->origin.x :rect->origin.x + rect->size.width];
  134.     }
  135.     }
  136.  
  137.     return self;
  138. }
  139.  
  140. - (BOOL)showRuler:(BOOL)showIt isHorizontal:(BOOL)isHorizontal
  141. /*
  142.  * Adds or removes a ruler from the view hierarchy.
  143.  * Returns whether or not it succeeded in doing so.
  144.  */
  145. {
  146.     id ruler;
  147.     BOOL isVisible;
  148.     NXRect cRect, rRect;
  149.  
  150.     isVisible = isHorizontal ? horizontalRulerIsVisible : verticalRulerIsVisible;
  151.     if ((showIt && isVisible) || (!showIt && !isVisible)) return NO;
  152.     if (showIt && !rulersMade && ![self makeRulers]) return NO;
  153.     ruler = isHorizontal ? hClipRuler : vClipRuler;
  154.  
  155.     if (!showIt && isVisible) {
  156.     [ruler removeFromSuperview];
  157.     if (isHorizontal) {
  158.         horizontalRulerIsVisible = NO;
  159.     } else {
  160.         verticalRulerIsVisible = NO;
  161.     }
  162.     } else if (showIt && !isVisible && ruler) {
  163.     [self addSubview:ruler];
  164.     [window disableDisplay];
  165.     [contentView getBounds:&cRect];
  166.     [hClipRuler getBounds:&rRect];
  167.     [hClipRuler setDrawOrigin:cRect.origin.x :rRect.origin.y];
  168.     [vClipRuler getBounds:&rRect];
  169.     [vClipRuler setDrawOrigin:rRect.origin.x :cRect.origin.y];
  170.     [window reenableDisplay];
  171.     if (isHorizontal) {
  172.         horizontalRulerIsVisible = YES;
  173.     } else {
  174.         verticalRulerIsVisible = YES;
  175.     }
  176.     }
  177.  
  178.     return YES;
  179. }
  180.  
  181. - adjustSizes
  182. {
  183.     id windelegate;
  184.     NXRect winFrame;
  185.  
  186.     windelegate = [window delegate];
  187.     if ([windelegate respondsTo:@selector(windowWillResize:toSize:)]) {
  188.     [window getFrame:&winFrame];
  189.     [windelegate windowWillResize:window toSize:&winFrame.size];
  190.     [window placeWindow:&winFrame];
  191.     }
  192.     [self resizeSubviews:(NXSize *)nil];
  193.  
  194.     return self;
  195. }
  196.  
  197. - showHorizontalRuler:(BOOL)flag
  198. {
  199.     if ([self showRuler:flag isHorizontal:YES]) [self adjustSizes];
  200.     return self;
  201. }
  202.  
  203. - showVerticalRuler:(BOOL)flag
  204. {
  205.     if ([self showRuler:flag isHorizontal:NO]) [self adjustSizes];
  206.     return self;
  207. }
  208.  
  209. - showHideRulers:sender
  210. /*
  211.  * If both rulers are visible, they are both hidden.
  212.  * Otherwise, both rulers are made visible.
  213.  */
  214. {
  215.     BOOL resize = NO;
  216.  
  217.     if (verticalRulerIsVisible && horizontalRulerIsVisible) {
  218.     resize = [self showRuler:NO isHorizontal:YES];
  219.     resize = [self showRuler:NO isHorizontal:NO] || resize;
  220.     } else {
  221.     if (!horizontalRulerIsVisible) resize = [self showRuler:YES isHorizontal:YES];
  222.     if (!verticalRulerIsVisible) resize = [self showRuler:YES isHorizontal:NO] || resize;
  223.     }
  224.     if (resize) [self adjustSizes];
  225.  
  226.     return self;
  227. }
  228.  
  229. /* ScrollView-specific stuff */
  230.  
  231. - free
  232. {
  233.     if (!horizontalRulerIsVisible) [hClipRuler free];
  234.     if (!verticalRulerIsVisible) [vClipRuler free];
  235.     return [super free];    
  236. }
  237.  
  238. - reflectScroll:cView
  239. /*
  240.  * We only reflect scroll in the contentView, not the rulers.
  241.  */
  242. {
  243.     if (cView == hClipRuler || cView == vClipRuler) return self;
  244.     return [super reflectScroll:cView];
  245. }
  246.  
  247. - tile
  248. /*
  249.  * Here is where we lay out the subviews of the ScrollView.
  250.  * Note the use of NXDivideRect() to "slice off" a section of
  251.  * a rectangle.  This is useful since the two scrollers each
  252.  * result in slicing a section off the contentView of the
  253.  * ScrollView.
  254.  */
  255. {
  256.     NXRect aRect, bRect, cRect;
  257.  
  258.     [super tile];
  259.  
  260.     if (horizontalRulerIsVisible || verticalRulerIsVisible) {
  261.     [contentView getFrame:&aRect];
  262.     [[self docView] getFrame:&cRect];
  263.     if (horizontalRulerIsVisible && hClipRuler) {
  264.         NXDivideRect(&aRect, &bRect, horizontalRulerWidth, NX_YMIN);
  265.         [hClipRuler setFrame:&bRect];
  266.         [[hClipRuler docView] sizeTo:cRect.size.width+verticalRulerWidth :bRect.size.height];
  267.     }
  268.     if (verticalRulerIsVisible && vClipRuler) {
  269.         NXDivideRect(&aRect, &bRect, verticalRulerWidth, NX_XMIN);
  270.         [vClipRuler setFrame:&bRect];
  271.         [[vClipRuler docView] sizeTo:bRect.size.width :cRect.size.height];
  272.     }
  273.     [contentView setFrame:&aRect];
  274.     }
  275.  
  276.     return self;
  277. }
  278.  
  279. - scrollClip:aClipView to:(const NXPoint *)aPoint
  280. /*
  281.  * This is sent to us instead of rawScroll:.
  282.  * We scroll the two rulers, then the clipView itself.
  283.  */
  284. {
  285.     NXRect rRect;
  286.  
  287.     if (horizontalRulerIsVisible && hClipRuler) {
  288.     [hClipRuler getBounds:&rRect];
  289.     rRect.origin.x = aPoint->x;
  290.     [hClipRuler rawScroll:&(rRect.origin)];
  291.     }
  292.     if (verticalRulerIsVisible && vClipRuler) {
  293.     [vClipRuler getBounds:&rRect];
  294.     rRect.origin.y = aPoint->y;
  295.     [vClipRuler rawScroll:&(rRect.origin)];
  296.     }
  297.  
  298.     [aClipView rawScroll:aPoint];
  299.  
  300.     return self;
  301. }
  302.  
  303. - descendantFrameChanged:sender
  304. /*
  305.  * Any time the docView is resized, this method is
  306.  * called to update the size of the rulers to be equal to
  307.  * the size of the docView.
  308.  */
  309. {
  310.     NXRect aRect, bRect, cRect;
  311.  
  312.     [super descendantFrameChanged:sender];
  313.     if (horizontalRulerIsVisible || verticalRulerIsVisible) {
  314.     [contentView getFrame:&aRect];
  315.     [[self docView] getFrame:&cRect];
  316.     if (horizontalRulerIsVisible && hClipRuler) {
  317.         NXDivideRect(&aRect, &bRect, horizontalRulerWidth, NX_YMIN);
  318.         [[hClipRuler docView] sizeTo:cRect.size.width+verticalRulerWidth :bRect.size.height];
  319.     }
  320.     if (verticalRulerIsVisible && vClipRuler) {
  321.         NXDivideRect(&aRect, &bRect, verticalRulerWidth, NX_XMIN);
  322.         [[vClipRuler docView] sizeTo:bRect.size.width :cRect.size.height];
  323.     }
  324.     }
  325.  
  326.     return self;
  327. }
  328.  
  329. @end
  330.